package httpDownload;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

public class Port {
	BufferedInputStream is;
	PrintWriter pw;
	long fileSize;
	int threadSize = 3; // number for downloadThread
	ArrayList<downloadThread> threads = new ArrayList<>();
	String fileName;
	String basePath;

	public Port(int i, String basePath) {
		threadSize = i;
		this.basePath = basePath;
	}

	public Port() {
	}

	public void begin(String url) {
		HttpHead head = convert(url);
		if (head == null) {
			System.out.println("enter a correct url");
			System.exit(-1);
		}
		Socket socket;
		try {
			socket = new Socket(head.getHost(), head.getPort());
			is = new BufferedInputStream(socket.getInputStream());
			pw = new PrintWriter(socket.getOutputStream());
			String strHead = head.toString();
			pw.print(strHead);
			pw.flush();
			fileSize = getSizeFromServer(is);
			System.out.println("fileSize = " + fileSize + "b");
			System.out.println("file path is " + fileName);
			is.close();
			pw.close();
			socket.close();
			if (fileSize == 0) {
				System.out.println("error : file size is 0!");
				System.exit(-1);
			}

			// task size for per thread
			long perSize = this.fileSize / threadSize;
			long begin = 0;
			long offset = perSize - 1;

			// 下载开始的时间
			long startD = System.currentTimeMillis();
			for (int i = 0; i < threadSize; i++) {
				downloadThread t = null;
				if (i + 1 == threadSize) {
					t = new downloadThread(head.copy(begin, fileSize - begin
							- 1), i, fileName);
				} else
					t = new downloadThread(head.copy(begin, offset), i,
							fileName);
				threads.add(t);
				begin += offset + 1;
				t.start();
			}

			// head.setBegin(0);
			// head.setOffset(fileSize - 1024);
			// head.setLen(fileSize - 1024 + 1);
			// downloadThread t1 = new downloadThread(head,0,fileName);
			// threads.add(t1);
			// t1.start();
			//
			// downloadThread t2 = new downloadThread(head.copy(fileSize - 1023,
			// 1022),1,fileName);
			// threads.add(t2);
			// t2.start();

			// 等待所有子进程完成并显示下载进度
			// byte num have been downloaded.
			long hasDown = 0;
			// byte num have been downloaded in last seconds
			long hasDownlastS = 0;
			long v = 1;
			int waitTime = 2000;
			while (true) {
				boolean flag = true;
				hasDown = 0;
				for (downloadThread t : threads) {
					if (t.isAlive()) {
						flag = false;
						// break;
					}
					hasDown += t.getProgress();
				}
				// System.out.println(hasDown);
				// System.out.print(hasDown + " " + hasDownlastS);
				v = (hasDown - hasDownlastS) / waitTime;
				System.out.print("["
						+ (long) ((double) hasDown / fileSize * 100)
						+ "%]------" + v + "kb/s");
				// 回退字符
				System.out.print("-----cost "
						+ (System.currentTimeMillis() - startD) / 1000 + "s ");
				if(v != 0){
					long ramainT = (fileSize - hasDown) / v / 1000;
				System.out.print("-----remaning " + ramainT
						+ "s                     ");    //this blank is MUST BE !
				}else{
					System.out.print("-----remaning CAN'T ASTIMAT ");
				}
//				backspaceByte();
				System.out.println();
				hasDownlastS = hasDown;
				if (flag)
					break;
				// check v per second
				try {
					Thread.sleep(waitTime);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			// 合并文件
			mergeFile();
			// 下载结束的时间
			long stopD = System.currentTimeMillis();
			// System.out.println("main thread end");
			System.out.println("\n+++++++++DOWN++++++++COST TIME "
					+ (stopD - startD) / 1000 + "s");

		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			System.out.println("UnknownHost,please check your input");
			// e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private void backspaceByte() {
		// TODO Auto-generated method stub
		for (int i = 0; i < 80; i++)
			System.out.print("\b");
	}

	private long getSizeFromServer(BufferedInputStream is) throws IOException {
		// TODO Auto-generated method stub
		String str;
		while ((str = readLine(is)) != null) {
			if (str.contains("Content-Length")
					&& str.indexOf("Content-Length") == 0) {
				return Long.parseLong(str.substring(16));
			}
		}
		return 0;
	}

	private String readLine(BufferedInputStream is) throws IOException {
		int buf;
		StringBuilder sb = new StringBuilder();
		while (true) {
			buf = is.read();
			// System.out.print((char)buf);
			if (buf == '\r') {
				// read '\n'
				is.read();
				break;
			}
			sb.append((char) buf);
		}

		return sb.length() != 0 ? sb.toString() : null;
	}

	// http://su.bdimg.com/static/superpage/img/logo_white.png
	private HttpHead convert(String url) {
		// TODO Auto-generated method stub
		HttpHead head = new HttpHead(url);
		if ((url.indexOf("http://") != 0) && (url.indexOf("https://") != 0))
			return null;
		url = url.substring(url.indexOf("//") + 2);
		// su.bdimg.com/static/superpage/img/logo_white.png
		// dig host name ,like su.bdimg.com
		head.setHost(url.substring(0, url.indexOf("/")));
		// dig port number,maybe dont have one
		if (url.indexOf(":") > 0) {
			String port = url.substring(url.indexOf(":") + 1, url.indexOf("/"));
			head.setPort(Integer.parseInt(port));
			head.setHost(head.getHost().split(":")[0]);
		}
		// /static/superpage/img/logo_white.png
		head.setRelativeUrl(url.substring(url.indexOf("/"), url.length()));

		// 提取文件名
		if (head.getHost().contains("baidu")) {
			// 百度云盘的链接
			fileName = "baiduyun_" + System.currentTimeMillis();
		} else {
			int lenq = url.indexOf("?") == -1 ? url.length() : url.indexOf("?");
			fileName = url.substring(url.lastIndexOf("/") + 1, lenq);
			if (fileName.length() > 30) {
				fileName = fileName.substring(0, 10);
			}
		}
		fileName = basePath + "/" + fileName;
		isContiued();
		return head;
	}
	
	//judge if continued task
	private void isContiued() {
		// TODO Auto-generated method stub
		int i = 0;
		while(true){
			File file = new File(fileName+"+"+i);
			if(file.exists()&&file.isFile()){
				i++;
			}
			else
				break;
		}
		if(i != 0)
			threadSize = i;
	}

	public void mergeFile() throws IOException {
		// System.out.println("start merge file");
		File file = new File(fileName);
		int fileC = 1;
		//不能简单的按照用户输入的文件名来建立文件，因为有可能存在同名的
		while(file.exists()){
			file = new File(fileName +"("+fileC+")");
		}
		FileOutputStream os = new FileOutputStream(file);
		FileInputStream is;
		byte[] buf = new byte[1024];
		for (int i = 0; i < threads.size(); i++) {
			// System.out.println(threads.get(i).getFileName());
			File tfile = new File(threads.get(i).getFileName());
			is = new FileInputStream(tfile);
			int tlen;
			while ((tlen = is.read(buf)) > 0) {
				os.write(buf, 0, tlen);
			}
			is.close();
		}
		os.close();
		fileC = 0;
		file = new File(fileName+"+"+fileC++);
		
		//delete buffer file
		while(file.exists()){
			file.delete();
			file = new File(fileName+"+"+fileC++);
		}
		// System.out.println("merge file end");
	}

	public static void main(String[] args) {
		int threadnr = 3;
		String basePath = System.getProperty("user.dir");
		String url = "";
		for (int i = 0; i < args.length; i++) {
			if (args[i].startsWith("-") && i < args.length - 1) {
				if (args[i].equals("-n")) {
					try {
						threadnr = Integer.parseInt(args[++i]);
					} catch (NumberFormatException e) {
						System.out.println("Thread number must is integer");
						System.exit(0);
					}
				} else if (args[i].equals("-p")) {
					File filet = new File(args[++i]);
					if (!filet.isDirectory()) {
						System.out.println("path error,please check you path");
						System.exit(0);
					}
					if (!filet.canWrite()) {
						System.out
								.println("sorry ,i don't have permission to write to this path");
						System.exit(0);
					}
					basePath = args[i];
				} else {
					System.out.println("sorry,unsurport command!");
					System.exit(0);
				}
			} else {
				if (args[i].startsWith("-")) {
					if (args[i].equals("-h") || args[i].equals("--help")) {
						Port.showCMD();
					} else {
						System.out.println("sorry,unsurport command!");
						System.exit(0);
					}
				} else if (args[i].startsWith("http://")
						|| args[i].startsWith("https://")) {
					url = args[i];
				} else {
					System.out.println("please enter a correct URL");
					System.out.println("you can enter -h check command list");
					System.exit(0);
				}
			}
		}
		Port p = new Port(threadnr, basePath);
		p.begin(url);
	}

	static public void showCMD() {
		System.out.println("The Http Downloader");
		System.out.println("any issues please send to huangyaobyte@gmail.com");
		System.out.println("-n   thread number to download,default is 3,if continue last task ,this argument diable");
		System.out
				.println("-p   the path to save file,default is the current path");
		System.out.println("-h --help   print help information");
	}
}
